#ifndef _CMEDIAFILE_H_
#define _CMEDIAFILE_H_

#include "pthread.h"
#include <map>
#include <mutex>
#include <qt_windows.h>
#include <stdint.h>
#include <string>


#define AVM_SUCCESS 0
#define AVM_FAILED -1
#define AVM_NOT_FOUND -2
#define AVM_NO_DEOCDER -3
#define AVM_NOT_OPEN -4

typedef struct _FRAME {
  /* Image data for this frame */
  unsigned char *data[3];
  /* Size of image data buffer */
  size_t data_bytes[3];
  /* Width of image in pixels */
  uint32_t width;
  /* Height of image in pixels */
  uint32_t height;
  /* Pixel data format */
  char fmt[16];
  int stride[3];
  /* pts */
  uint64_t pts;
  int size;
  uint64_t index;
  int state;
} AVMFrame_t;

typedef struct _MediaInfo {
  uint32_t stream_cnt;
  uint32_t video_index;
  uint32_t width;
  uint32_t height;
  int64_t bit_rate;
  int64_t total_frames;
  float fps;
  int64_t duration;
  char fmt[64];
} AVMMediaInfo_t;

typedef void (*FrameCb)(AVMFrame_t *pFrame, void *userdata);
typedef void (*CropProgress)(void *usr, int cur, int total);
typedef std::map<double, std::string> SEI_MAP;

extern "C" {
#include "libavcodec/packet.h"
#include "libavcodec/avcodec.h"
#include "libavfilter/avfilter.h"
#include "libavformat/avformat.h"
#include "libavutil/error.h"
#include "libavutil/frame.h"
#include "libavutil/imgutils.h"
#include "libswscale/swscale.h"
}

class CMediaFile {
  typedef struct EncCtx_ {
    int enc_type;
    bool is_init;
    bool is_write_file;
    AVCodecContext *codec_ctx;
    AVFormatContext *fmt_ctx;
    AVPacket *pkt;
    AVStream *stream;
    const AVCodec *codec;
  } EncCtx;

public:
  CMediaFile();
  ~CMediaFile();

public:
  enum AVM_STATE_ {
    AVM_STATE_CLOSE,
    AVM_STATE_OPEN,
    AVM_STATE_START,
    AVM_STATE_PAUSE,
    AVM_STATE_END
  };
  enum CROP_TYPE_ { CROP_TYPE_JPEG = 0, CROP_TYPE_VIDEO };

public:
  int Open(std::string url, HWND hWnd);
  int Close();
  int SetFrameValidCallBackFunc(FrameCb cb, void *userdata);
  int Play();
  int Pause();
  int GetInfo(AVMMediaInfo_t *info);
  int SeekByTime(uint64_t dst_time_in_us);
  int SeekByFrame(uint64_t dst_frame);
  int GetState() { return state_; };
  int Crop(std::string file, int type, int start, int length, int interval,
           CropProgress pFunc, CMediaFile *avm, void *usr);
  int StopCrop();

public:
  AVFormatContext *av_fmt_ctx_;
  AVCodecContext *av_codec_ctx_;
  AVFrame *frame_codec_;
  AVFrame *frame_yuv_;
  AVPacket *av_packet_;
  uint8_t *output_buf_;
  struct SwsContext *av_conv_ctx_;
  int video_index_;
  bool display_;
  pthread_t thread_codec_;
  BOOL thread_watch_;
  FrameCb frame_cb_func_;
  void *frame_cb_data_;
  int state_;
  uint64_t fps_ctrl_ms_;
  bool stop_;
  std::mutex mutex_lock_;
  bool seeking_;

public:
  static void *thread_codec_func(void *param);

private:
  int InitOutputCtx(EncCtx *ctx, std::string file, int type, int width,
                    int height);
  int InitJpegOutputCtx(EncCtx *ctx, std::string file, int width, int height);
  int InitVideoOutputCtx(EncCtx *ctx, std::string file, int width, int height);
  int DestroyOutputCtx(EncCtx *ctx);
  int InsertFrames(std::string file, AVFrame *pFrame, EncCtx *ctx);
public:
  static int GetRadarDataInSEI(const char* file, SEI_MAP &sei_map);
  static int SaveRadarDatatoFile(const char* file, SEI_MAP radar_data);
  static int ReadRadarDataFromFile(const char* file, SEI_MAP& radar_data);
};

#endif